package auth

import (
	"strings"
)

/*
将权限表现为代码的方式，并且提供相应的验证功能
 */

// 使用编码表示一组(多条)权限
var (
	Sep = "," // 分隔多条权限的标记
	Dot = "." // 分隔一条权限内各节
	Wildcard = "*" // 通配符，代替权限中末尾的若干节
)

// 将多个编码整合成一个，并去掉重复的权限
func JoinAccess(cs ...string) string {
	// 将所有编码分隔并保存在数组中
	ps := make([]string, 0)
	for _, n := range cs {
		ps = append(ps, strings.Split(n, Sep)...)
	}
	// 使用map去除重复权限
	km := make(map[string]bool)
	for _, p := range ps {
		p = strings.TrimSpace(p)
		if p != "" {
			km[p] = true
		}
	}
	ps = make([]string, 0)
	for k, _ := range km {
		ps = append(ps, k)
	}
	// 拼接成新的权限
	return strings.Join(ps, Sep)
}

/*
节点
A.a.1.u

* 有权访问
A.a.* 有权访问
A.a.1 无权访问
A.a.1.u 有权访问
A.a.1.u.11 有权访问

以通配符结尾的权限，越短权限越大，可以访问下层的所有节点
没有通配符的权限，越长权限越大，也可以访问上面各层的节点
*/
// 检查c是否有n指定的权限
func CheckAccess(c, n string) bool {
	ps := strings.Split(c, Sep)
	for _, p := range ps {
		p = strings.TrimSpace(p)
		// p是已有的权限,n是节点要求的权限
		if p != "" {
			if p == Wildcard { // 与通配符相同，允许访问任何节点
				return true
			} else if strings.HasSuffix(p, Dot+Wildcard) { // 已通配符结束，允许访问指定的下级节点
				if strings.HasPrefix(n+Dot, strings.TrimSuffix(p, Wildcard)) { // 通过前缀判断n是不是包含p，n和p都要以Dot结尾
					return true
				}
			} else if strings.HasPrefix(p+Dot, n+Dot) { // 有下级节点的权限，则也允许访问当前节点
				return true
			}
		}
	}
	return false
}

